import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import type { Secret, SignOptions } from 'jsonwebtoken';

// 扩展Request类型以包含用户信息
declare global {
  namespace Express {
    interface Request {
      user?: {
        id: string;
        username?: string;
        name?: string;
        email?: string;
        role?: string;
        roles?: string[];
      };
    }
  }
}

// JWT密钥，生产环境应使用环境变量
// 保持与 auth 路由签发使用的 AUTH_SECRET 一致，避免验证失败
const AUTH_SECRET: Secret = (process.env.AUTH_SECRET as unknown as Secret) || 'your-secret-key';

// 认证中间件
export const authenticateToken = (req: Request, res: Response, next: NextFunction) => {
  try {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

    if (!token) {
      return res.status(401).json({
        success: false,
        message: '访问令牌缺失'
      });
    }

    // 验证JWT令牌
    jwt.verify(token, AUTH_SECRET, (err: any, decoded: any) => {
      if (err) {
        console.error('Token验证失败:', err.message);
        return res.status(403).json({
          success: false,
          message: '访问令牌无效或已过期'
        });
      }

      // 将用户信息添加到请求对象
      req.user = {
        id: decoded.id || decoded.userId,
        username: decoded.username || decoded.name,
        name: decoded.name || decoded.username,
        email: decoded.email,
        role: decoded.role
      };

      next();
    });
  } catch (error) {
    console.error('认证中间件错误:', error);
    return res.status(500).json({
      success: false,
      message: '认证服务异常'
    });
  }
};

// 生成JWT令牌的辅助函数
export const generateToken = (user: {
  id: string;
  username?: string;
  name?: string;
  email?: string;
  role?: string;
}, expiresIn: SignOptions['expiresIn'] = '24h') => {
  return jwt.sign(
    {
      id: user.id,
      userId: user.id,
      username: user.username || user.name,
      name: user.name || user.username,
      email: user.email,
      role: user.role || 'user'
    },
    AUTH_SECRET,
    { expiresIn }
  );
};